package com.dinim.physics2D;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import com.dinim.common.StopWatch;
import com.dinim.object.IObject2D;

public class OBBContactResolver {

    public OBBContactResolver() {
    }
    
    public OBBContactResolver(List objects){
        this.objects = objects;
    }
    
    private List objects = new ArrayList();
    
    public void addObject(IObject2D object){
        objects.add(object);
    }
    
    private class ContactGroup{

//        public String toString() {
//            String str = superobject.hashCode() + " contains\n";
//            Iterator it = subobjects.iterator();
//            while(it.hasNext()){
//                str = str + " - " + it.next().hashCode() + "\n";
//            }
//            return str;
//        }

        private IObject2D superobject;
        private List subobjects;
        
        public boolean contains(Object object){
            if(subobjects.contains(object)){
                return true;
            }else{
                return false;
            }
        }
        
        public ContactGroup(IObject2D superobject) {
            this.superobject = superobject;
            subobjects = new ArrayList();
        }
        
        public void addSubObject(IObject2D subobject){
            subobjects.add(subobject);
        }
        
    }
    
    private List getResolvedContactGroups(Comparator comparator, String direction){
        Collections.sort(objects, comparator);
        
        List contactGroups = new ArrayList();
        for(int i = 0; i < objects.size(); i++){
            IObject2D obj = (IObject2D)objects.get(i);
            IBoundingBox2D bb = obj.getBoundingBox();
            ContactGroup cg = new ContactGroup(obj);
            int j = 0;
            boolean run = true;
            while(run && (objects.size()-1 > i+j)){
                j = j + 1;
                IObject2D nextObject = (IObject2D)objects.get(i+j);
                double thisObjectValue;
                double nextObjectValue;
                if(direction.equals("x")){
                    thisObjectValue = bb.getRight();
                    nextObjectValue = nextObject.getBoundingBox().getLeft();
                }else if(direction.equals("y")){
                    thisObjectValue = bb.getBottom();
                    nextObjectValue = nextObject.getBoundingBox().getTop();
                }else{
                    throw new RuntimeException("\"" + direction + "\"" + "is not a valid direction");
                }
                
                if(thisObjectValue > nextObjectValue){
                    cg.addSubObject(nextObject);
                } else {
                    run = false;
                }
            }
            contactGroups.add(cg);
        }
        return contactGroups;
    }
    
    public void resolve(){

        List resolvedCgX = getResolvedContactGroups(new Comparator(){
                                                        public int compare(Object o1, Object o2) {
                                                            IObject2D obj1 = (IObject2D)o1;
                                                            IObject2D obj2 = (IObject2D)o2;
                                                            double top1 = obj1.getBoundingBox().getLeft();
                                                            double top2 = obj2.getBoundingBox().getLeft();
                                                            return (int)Math.round(top1 - top2);
                                                        }
                                                        
                                                    }, "x");
        
        List resolvedCgY = getResolvedContactGroups(new Comparator(){
                                                        public int compare(Object o1, Object o2) {
                                                            IObject2D obj1 = (IObject2D)o1;
                                                            IObject2D obj2 = (IObject2D)o2;
                                                            double top1 = obj1.getBoundingBox().getTop();
                                                            double top2 = obj2.getBoundingBox().getTop();
                                                            return (int)Math.round(top1 - top2);
                                                        }
                                                        
                                                    }, "y");

        Comparator cgComparator = new Comparator(){
            public int compare(Object o1, Object o2) {
                ContactGroup cg1 = (ContactGroup)o1;
                ContactGroup cg2 = (ContactGroup)o2;
                double top1 = cg1.superobject.getBoundingBox().getTop();
                double top2 = cg2.superobject.getBoundingBox().getTop();
                return (int)Math.round(top1 - top2);
            }
        };
        
        Collections.sort(resolvedCgX, cgComparator);
        Collections.sort(resolvedCgY, cgComparator);
        
        System.out.println("cgs x: " + resolvedCgX.size());
        System.out.println("cgs y: " + resolvedCgY.size());
        
        for(int i = 0; i < resolvedCgX.size(); i++){
            for(int j = 0; j < resolvedCgX.size(); j++){
                if(((ContactGroup)resolvedCgX.get(j)).superobject.hashCode() == ((ContactGroup)resolvedCgY.get(j)).superobject.hashCode()){
                    //System.out.println(true);
                } else {
                    System.out.println(false);
                }
            }
        }
        
        
        List collidingObjects = new ArrayList();
        
        for(int i = 0; i < resolvedCgX.size(); i++){
            ContactGroup cgx = (ContactGroup)resolvedCgX.get(i);
            ContactGroup cgy = (ContactGroup)resolvedCgY.get(i);

            List co = new ArrayList();
            if(cgx.subobjects.size() < cgy.subobjects.size()){
                co = resolveContactGroups(cgx, cgy);
            } else {
                co = resolveContactGroups(cgy, cgx);
            }

            collidingObjects.addAll(co);

        }
        System.out.println(collidingObjects.size());
        
        List sammler = new ArrayList(){

            public boolean contains(Object elem) {
                IObject2D[] group = (IObject2D[])elem;
                return super.contains(elem);
            }
            
        };
        
//        getObjectContacts(resolvedCgX);
//        getObjectContacts(resolvedCgY);
        
    }

    private List resolveContactGroups(ContactGroup smaller, ContactGroup bigger){
        List collidingObjects = new ArrayList();
        
        IObject2D superobject = smaller.superobject;
        superobject = bigger.superobject;
        
        System.out.println("Analyizing contactgroups...");
        System.out.println("Smaller one: " + smaller.subobjects.size() + ", super: " + smaller.superobject.hashCode());
        System.out.println("Bigger one: " + bigger.subobjects.size() + ", super:  " + bigger.superobject.hashCode());
        
        int counter = 0;
        for(int i = 0; i < smaller.subobjects.size(); i++){
            
            if(bigger.subobjects.contains(smaller.subobjects.get(i))){
                collidingObjects.add(new IObject2D[]{superobject, (IObject2D)smaller.subobjects.get(i)});
                //counter++;
            }
        }
        System.out.println("added: " + counter);
        return collidingObjects;
    }
    
    private void getObjectContacts(List contactGroups, List sammler){
        //List objectContacts = new ArrayList();
        for(int i = 0; i < contactGroups.size(); i++){
            IObject2D superobject = ((ContactGroup)contactGroups.get(i)).superobject;
            List subobjects = ((ContactGroup)contactGroups.get(i)).subobjects;
            for(int j = 0; j < subobjects.size(); j++){
                IObject2D subobject = (IObject2D)subobjects.get(j);
                if(superobject.hashCode()<subobject.hashCode()){
                    sammler.add(new IObject2D[]{superobject, subobject});
                }else{
                    sammler.add(new IObject2D[]{subobject, superobject});
                }
            }
        }
        //return objectContacts;
    }
    
}
